package com.pingan.haofang.searchcloud.monitor.service.impl;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONObject;
import com.pingan.haofang.searchcloud.api.StorageCluster;
import com.pingan.haofang.searchcloud.api.constants.EngineType;
import com.pingan.haofang.searchcloud.api.facade.CollectionManageFacade;
import com.pingan.haofang.searchcloud.common.configuration.ClusterNodeProperties;
import com.pingan.haofang.searchcloud.common.configuration.ClusterProperties;
import com.pingan.haofang.searchcloud.common.constants.Constants;
import com.pingan.haofang.searchcloud.common.constants.Status;
import com.pingan.haofang.searchcloud.common.dto.PageDTO;
import com.pingan.haofang.searchcloud.mail.constants.MailConstants;
import com.pingan.haofang.searchcloud.mail.dto.MailDto;
import com.pingan.haofang.searchcloud.mail.service.MailService;
import com.pingan.haofang.searchcloud.monitor.constants.MonitorIndicator;
import com.pingan.haofang.searchcloud.monitor.constants.NodeStatus;
import com.pingan.haofang.searchcloud.monitor.constants.WarningType;
import com.pingan.haofang.searchcloud.monitor.dao.DashboardResourceInfoDao;
import com.pingan.haofang.searchcloud.monitor.dao.DashboardWarningConfigDao;
import com.pingan.haofang.searchcloud.monitor.dao.DashboardWarningHistoryDao;
import com.pingan.haofang.searchcloud.monitor.domain.DashboardResourceInfo;
import com.pingan.haofang.searchcloud.monitor.domain.DashboardWarningConfig;
import com.pingan.haofang.searchcloud.monitor.domain.DashboardWarningHistory;
import com.pingan.haofang.searchcloud.monitor.dto.ChartReportResultDTO;
import com.pingan.haofang.searchcloud.monitor.dto.ChartReportXYDTO;
import com.pingan.haofang.searchcloud.monitor.dto.ChartReportXYMapDTO;
import com.pingan.haofang.searchcloud.monitor.dto.DashboardResourceDTO;
import com.pingan.haofang.searchcloud.monitor.dto.DashboardResourceInfoDTO;
import com.pingan.haofang.searchcloud.monitor.dto.DashboardResourceInfoQueryDTO;
import com.pingan.haofang.searchcloud.monitor.dto.DashboardResourceInfoResultDTO;
import com.pingan.haofang.searchcloud.monitor.dto.DiskConditonDTO;
import com.pingan.haofang.searchcloud.monitor.dto.WarningModelDTO;
import com.pingan.haofang.searchcloud.monitor.service.DashboardResourceInfoService;
import com.pingan.haofang.searchcloud.solr.utils.DateUtils;

/**
 * @author EX-LIUXIANWEN001
 * @date 2018/10/18
 * @since 1.0.0
 */
@Service
public class DashboardResourceInfoServiceImpl implements DashboardResourceInfoService {

    static Logger LOG = LoggerFactory.getLogger(DashboardResourceInfoServiceImpl.class);

    @Autowired
    private DashboardResourceInfoDao dashboardResourceInfoDao;

    @Autowired
    private ClusterProperties clusterProperties;

    @Autowired
    private ClusterNodeProperties clusterNodeProperties;

    @Autowired
    private DashboardWarningHistoryDao dashboardWarningHistoryDao;

    @Autowired
    private DashboardWarningConfigDao dashboardWarningConfigDao;

    @Autowired
    private CollectionManageFacade collectionManageFacade;

    @Value("${dashboard.report.env}")
    private String env;

    @Autowired
    private MailService mailService;

    private EntityManager entityManager;

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public void saveDashboardResourceInfo() {
        List<DashboardResourceInfo> resourceInfoList = new ArrayList<>();
        try {
            resourceInfoList = getDashboardResourceInfo();
        } catch (Exception e) {
            LOG.info("采集硬盘数据失败", e.getMessage());
        }

        for (DashboardResourceInfo dashboardResourceInfo : resourceInfoList) {
            dashboardResourceInfoDao.saveAndFlush(dashboardResourceInfo);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Map<String, List<ChartReportResultDTO>> queryDashboardResourceList(DashboardResourceInfoQueryDTO condition) {

        StringBuilder sql = this.getPreSqlString();
        Map<String, Object> paramMap = new HashMap<>();
        this.setParameters(sql, paramMap, condition);
        this.addFixSql(sql);
        String sql_ = sql.toString();

        List<DashboardResourceInfoDTO> pageDTO = dashboardResourceInfoDao.getConditionList(paramMap, sql_,
                DashboardResourceInfoDTO.class, entityManager);

        List<DashboardResourceInfoResultDTO> dashboardResourceInfoResultDTOList =
                handlerDashboardResourceByListData(pageDTO, condition);
        Map<String, List<ChartReportResultDTO>> map =
                handlerDashboardResourceByData(dashboardResourceInfoResultDTOList);
        return map;
    }

    @Override
    @Transactional(readOnly = true)
    public PageDTO<DashboardResourceInfoResultDTO> queryDashboardResourceView(DashboardResourceInfoQueryDTO condition) {

        StringBuilder sql = this.getPreSqlString();
        Map<String, Object> paramMap = new HashMap<>();
        this.setParameters(sql, paramMap, condition);
        this.addFixSqls(sql);
        String sql_ = sql.toString();

        List<DashboardResourceInfoDTO> pageDTO = dashboardResourceInfoDao.getConditionList(paramMap, sql_,
                DashboardResourceInfoDTO.class, entityManager);

        Map<String, Object> resultMap = handlerDashboardResourceByPageData(pageDTO, condition);

        List<DashboardResourceInfoResultDTO> list = (List<DashboardResourceInfoResultDTO>) resultMap.get("result");

        return PageDTO.builder(list).pageNo((int) resultMap.get("pageNo")).pageSize((int) resultMap.get("pageRowNum"))
                .totalPages((int) resultMap.get("totalPageNum")).totalRecords((int) resultMap.get("totalRowNum"))
                .build();

    }

    private StringBuilder getPreSqlString() {
        StringBuilder sql = new StringBuilder(
                "SELECT health_num,cluster_name,node_num,health_rate,create_time,acquisition_time,node_ips,disk_sizes,disk_useds "
                        + "from( "
                        + "SELECT a.health_num,a.cluster_name,a.node_num,a.health_rate,a.create_time,a.acquisition_time,b.node_ips,b.disk_sizes,b.disk_useds from "
                        + "(select count(1) AS health_num,cluster_name,node_num,FORMAT(count(1) / node_num, 2) AS health_rate,create_time,acquisition_time    "
                        + "       from  t_dashboard_resource_info where status=0 GROUP by cluster_name,acquisition_time   ) a "
                        + "LEFT JOIN  " + "(SELECT "
                        + "  cluster_name,GROUP_CONCAT(node_ip) as node_ips,GROUP_CONCAT(disk_size) as disk_sizes,GROUP_CONCAT(disk_used) as disk_useds,acquisition_time    "
                        + "FROM " + " t_dashboard_resource_info " + "WHERE " + " STATUS = 0 " + "GROUP BY "
                        + " cluster_name,acquisition_time   )b on a.cluster_name=b.cluster_name and a.acquisition_time   =b.acquisition_time      "
                        + ")c   where 1=1 ");
        return sql;
    }

    private void addFixSql(StringBuilder sql) {
        sql.append("  order by acquisition_time");
    }

    private void addFixSqls(StringBuilder sql) {
        sql.append("  order by acquisition_time desc");
    }

    private void setParameters(StringBuilder sql, Map<String, Object> paramMap,
            DashboardResourceInfoQueryDTO condition) {
        // 日期查询
        sql.append(" and DATE_FORMAT(acquisition_time,'%Y-%m-%d')= :date");
        paramMap.put("date", condition.getDate());

        // 集群名称
        if (condition.getClusterName() != null) {
            sql.append(" and cluster_name= :clusterName");
            paramMap.put("clusterName", condition.getClusterName());
        }

        // 健康率 小
        if (condition.getHealthRateSmall() != null) {
            sql.append(" and health_rate>= :health_rate_small");
            paramMap.put("health_rate_small", (double) condition.getHealthRateSmall() / 100);
        }
        // 健康率 大
        if (condition.getHealthRateLarge() != null) {
            sql.append(" and health_rate<= :health_rate_large");
            paramMap.put("health_rate_large", (double) condition.getHealthRateLarge() / 100);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public DashboardResourceDTO queryDashboardResource() {
        StringBuilder sql = new StringBuilder(
                "SELECT acquisition_time ,GROUP_CONCAT(cluster_name SEPARATOR ';') cluster_names, GROUP_CONCAT(health_rate SEPARATOR ';') health_rates,GROUP_CONCAT(node_ips) node_ips, "
                        + "GROUP_CONCAT(disk_occupancys) disk_occupancys " + "from( "
                        + "SELECT a.health_num,a.cluster_name,a.node_num,a.health_rate,a.create_time,a.acquisition_time   ,b.node_ips,b.disk_occupancys from "
                        + "(select count(1) AS health_num,cluster_name,node_num,CONCAT(FORMAT((count(1) / node_num)*100, 0),'%' )AS health_rate,create_time,acquisition_time    "
                        + "       from  t_dashboard_resource_info where status=0 GROUP by cluster_name,acquisition_time   ) a "
                        + "LEFT JOIN  " + "(SELECT "
                        + "  cluster_name,GROUP_CONCAT(node_ip) as node_ips,GROUP_CONCAT(disk_occupancy) as disk_occupancys,acquisition_time    "
                        + "FROM "
                        + " (select cluster_name,node_ip,CONCAT(FORMAT((disk_used / disk_size)*100, 2),'%' )AS disk_occupancy,acquisition_time   from  t_dashboard_resource_info WHERE STATUS = 0)c "
                        + "GROUP BY "
                        + " cluster_name,acquisition_time   )b on a.cluster_name=b.cluster_name and a.acquisition_time   =b.acquisition_time      "
                        + ")d     group by acquisition_time  order by acquisition_time desc LIMIT 1 ");

        List<DashboardResourceDTO> pageDTO = dashboardResourceInfoDao.getConditionList(null, sql.toString(),
                DashboardResourceDTO.class, entityManager);

        if (pageDTO.size() > 0) {
            return handlerDashboardResourceData(pageDTO.get(0));
        } else {
            return new DashboardResourceDTO();
        }
    }

    /**
     * 总览图 健康率 节点率
     *
     * @param dto
     * @param
     */
    private DashboardResourceDTO handlerDashboardResourceData(DashboardResourceDTO dto) {

        Map<String, String> mapHealthRate = new HashMap<>(16);

        Map<String, String> mapDiskOccupancy = new HashMap<>(16);

        if (null != dto.getClusterNames() && null != dto.getHealthRates()) {
            List<String> listClusterNames = Arrays.asList(dto.getClusterNames().split(";"));

            List<String> listHealthRates = Arrays.asList(dto.getHealthRates().split(";"));
            for (int index = 0; index < listClusterNames.size(); index++) {
                mapHealthRate.put(listClusterNames.get(index), listHealthRates.get(index));
            }
            dto.setMapHealthRate(mapHealthRate);
        }
        if (null != dto.getNodeIps() && null != dto.getDiskOccupancys()) {
            List<String> nodeIps = Arrays.asList(dto.getNodeIps().split(","));
            List<String> diskSizes = Arrays.asList(dto.getDiskOccupancys().split(","));
            for (int index = 0; index < nodeIps.size(); index++) {
                mapDiskOccupancy.put(nodeIps.get(index), diskSizes.get(index));
            }
            dto.setMapDiskOccupancy(mapDiskOccupancy);
        }
        return dto;
    }

    /**
     * 处理集群与节点对应数据 不分页
     *
     * @param dtoList
     * @param condition
     */
    private List<DashboardResourceInfoResultDTO> handlerDashboardResourceByListData(
            List<DashboardResourceInfoDTO> dtoList, DashboardResourceInfoQueryDTO condition) {

        List<DashboardResourceInfoResultDTO> dtos = new ArrayList<>();

        if (!CollectionUtils.isEmpty(dtoList)) {
            for (DashboardResourceInfoDTO dto : dtoList) {
                DashboardResourceInfoResultDTO dto1 = new DashboardResourceInfoResultDTO();

                dto1.setDate(DateUtils.formatDate(dto.getAcquisitionTime(), "yyyy-MM-dd HH:mm"));
                dto1.setClusterName(dto.getClusterName());
                dto1.setHealthNum(dto.getHealthNum());
                dto1.setNodeNum(dto.getNodeNum());
                dto1.setHealthRate(Double.valueOf(dto.getHealthRate()) * 100);

                List<DiskConditonDTO> diskConditonDTOS = getDiskConditonInfo(dto.getNodeIps(), dto.getDiskSizes(),
                        dto.getDiskUseds(), dto.getClusterName(), condition);

                dto1.setDiskConditonDTOList(diskConditonDTOS);

                // 磁盘占用率删选
                if (!checkDashboardResourceInfoByDiskOccupancy(diskConditonDTOS, condition)) {
                    continue;
                }
                dtos.add(dto1);
            }
        }

        return dtos;
    }

    /**
     * 磁盘占用率删选
     *
     * @param diskConditonDTOS
     * @param condition
     */
    private boolean checkDashboardResourceInfoByDiskOccupancy(List<DiskConditonDTO> diskConditonDTOS,
            DashboardResourceInfoQueryDTO condition) {
        boolean flag = false;
        // 磁盘占用率删选
        if (null != condition.getDiskOccupancySmall() && null != condition.getDiskOccupancyLarge()) {
            for (DiskConditonDTO dto2 : diskConditonDTOS) {
                double diskOccupancys = dto2.getDiskOccupancy();
                if ((double) condition.getDiskOccupancyLarge() >= diskOccupancys
                        && diskOccupancys >= (double) condition.getDiskOccupancySmall()) {
                    flag = true;
                    break;
                }
            }
        } else if (null != condition.getDiskOccupancySmall()) {
            for (DiskConditonDTO dto2 : diskConditonDTOS) {
                double diskOccupancys = dto2.getDiskOccupancy();
                if (diskOccupancys >= (double) condition.getDiskOccupancySmall()) {
                    flag = true;
                    break;
                }
            }
        } else if (null != condition.getDiskOccupancyLarge()) {
            for (DiskConditonDTO dto2 : diskConditonDTOS) {
                double diskOccupancys = dto2.getDiskOccupancy();
                if ((double) condition.getDiskOccupancyLarge() >= diskOccupancys) {
                    flag = true;
                    break;
                }
            }
        } else {
            flag = true;
        }
        return flag;
    }

    /**
     * 视图数据处理 把数据格式处理成前端画图约定的格式
     *
     * @param dtoList
     */
    private Map<String, List<ChartReportResultDTO>>
            handlerDashboardResourceByData(List<DashboardResourceInfoResultDTO> dtoList) {

        Map<String, List<ChartReportResultDTO>> map = new HashMap<>();

        List<ChartReportXYDTO> list = dtoList.stream().map(dto -> {
            ChartReportXYDTO chartReportXYDTO = new ChartReportXYDTO();
            chartReportXYDTO.setName(dto.getClusterName());
            chartReportXYDTO.setX(dto.getDate());
            chartReportXYDTO.setY(dto.getHealthRate());
            return chartReportXYDTO;
        }).collect(Collectors.toList());

        List<ChartReportXYDTO> list1 = new ArrayList<>();
        for (DashboardResourceInfoResultDTO dto : dtoList) {
            List<DiskConditonDTO> diskConditonDTOS = dto.getDiskConditonDTOList();
            for (DiskConditonDTO diskConditonDTO : diskConditonDTOS) {
                ChartReportXYDTO chartReportXYDTO = new ChartReportXYDTO();
                chartReportXYDTO.setName(diskConditonDTO.getNodeIp());
                chartReportXYDTO.setX(dto.getDate());
                chartReportXYDTO.setY(diskConditonDTO.getDiskOccupancy());
                list1.add(chartReportXYDTO);
            }
        }

        Map<String, List<ChartReportXYDTO>> diskOccupancyRateMap =
                list1.stream().collect(Collectors.groupingBy(ChartReportXYDTO::getName));

        Map<String, List<ChartReportXYDTO>> sorlHealthRateMap =
                list.stream().collect(Collectors.groupingBy(ChartReportXYDTO::getName));

        // 健康率视图
        List<ChartReportResultDTO> sorlHealthRateList = sorlHealthRateMap.entrySet().stream().map(x -> {
            ChartReportResultDTO chartReportResultDTO = new ChartReportResultDTO();
            chartReportResultDTO.setName(x.getKey());
            List<ChartReportXYMapDTO> list2 = x.getValue().stream().map(t -> {
                ChartReportXYMapDTO chartReportXYMapDTO = new ChartReportXYMapDTO();
                chartReportXYMapDTO.setX(t.getX());
                chartReportXYMapDTO.setY(t.getY());
                return chartReportXYMapDTO;
            }).collect(Collectors.toList());
            chartReportResultDTO.setXyMapList(list2);
            return chartReportResultDTO;
        }).collect(Collectors.toList());

        // 磁盘使用率视图
        List<ChartReportResultDTO> diskOccupancyRateList = diskOccupancyRateMap.entrySet().stream().map(x -> {
            ChartReportResultDTO chartReportResultDTO = new ChartReportResultDTO();
            chartReportResultDTO.setName(x.getKey());
            List<ChartReportXYMapDTO> list2 = x.getValue().stream().map(t -> {
                ChartReportXYMapDTO chartReportXYMapDTO = new ChartReportXYMapDTO();
                chartReportXYMapDTO.setX(t.getX());
                chartReportXYMapDTO.setY(t.getY());
                return chartReportXYMapDTO;
            }).collect(Collectors.toList());
            chartReportResultDTO.setXyMapList(list2);
            return chartReportResultDTO;
        }).collect(Collectors.toList());

        map.put(MonitorIndicator.HARDWARE.DISK_OCCUPANCY_RATE, diskOccupancyRateList);
        map.put(MonitorIndicator.HARDWARE.SOLR_HEALTH_RATE, sorlHealthRateList);
        return map;
    }

    /**
     * 处理集群与节点对应数据 分页
     *
     * @param dtoList
     * @param condition
     */
    private Map<String, Object> handlerDashboardResourceByPageData(List<DashboardResourceInfoDTO> dtoList,
            DashboardResourceInfoQueryDTO condition) {
        Map<String, Object> retMap = new HashMap<>();

        List<DashboardResourceInfoResultDTO> dtos = new ArrayList<>();

        if (!CollectionUtils.isEmpty(dtoList)) {
            for (DashboardResourceInfoDTO dto : dtoList) {
                DashboardResourceInfoResultDTO dto1 = new DashboardResourceInfoResultDTO();

                dto1.setDate(DateUtils.formatDate(dto.getAcquisitionTime(), "yyyy-MM-dd HH:mm"));
                dto1.setClusterName(dto.getClusterName());
                dto1.setHealthNum(dto.getHealthNum());
                dto1.setNodeNum(dto.getNodeNum());
                dto1.setHealthRate(Double.valueOf(dto.getHealthRate()) * 100);

                List<DiskConditonDTO> diskConditonDTOS = getDiskConditonInfo(dto.getNodeIps(), dto.getDiskSizes(),
                        dto.getDiskUseds(), dto.getClusterName(), condition);

                dto1.setDiskConditonDTOList(diskConditonDTOS);

                // 磁盘占用率筛选
                if (!checkDashboardResourceInfoByDiskOccupancy(diskConditonDTOS, condition)) {
                    continue;
                }
                dtos.add(dto1);
            }
            return getPagingResultMap(dtos, condition.getPageNo(), condition.getPageSize());
        } else {
            retMap.put("result", Collections.emptyList());
            retMap.put("pageNo", 0);
            retMap.put("pageRowNum", 0);
            retMap.put("totalRowNum", 0);
            retMap.put("totalPageNum", 0);
            return retMap;
        }
    }

    /**
     * @param currPageNo 页面传入的页号，从一开始
     * @param pageSize 每页记录数
     */
    public <T> Map<String, Object> getPagingResultMap(List<T> list, Integer currPageNo, Integer pageSize) {
        Map<String, Object> retMap = new HashMap<>();

        // 每页显示多少条记录
        int currentPage; // 当前第几页数据

        int totalRecord = list.size(); // 一共多少条记录

        if (totalRecord > 0) {
            int totalPage = totalRecord % pageSize; // 一共多少页
            if (totalPage > 0) {
                totalPage = totalRecord / pageSize + 1;
            } else {
                totalPage = totalRecord / pageSize;
            }

            // 当前第几页数据
            currentPage = totalPage < currPageNo ? totalPage : currPageNo;

            // 起始索引
            int fromIndex = pageSize * (currentPage - 1);

            // 结束索引
            int toIndex = pageSize * currentPage > totalRecord ? totalRecord : pageSize * currentPage;

            List<T> result = list.subList(fromIndex, toIndex);

            retMap.put("result", result);
            retMap.put("pageNo", currentPage);
            retMap.put("pageRowNum", result.size());
            retMap.put("totalRowNum", totalRecord);
            retMap.put("totalPageNum", totalPage);
        } else {
            retMap.put("result", Collections.emptyList());
            retMap.put("pageNo", 0);
            retMap.put("pageRowNum", 0);
            retMap.put("totalRowNum", 0);
            retMap.put("totalPageNum", 0);
        }
        return retMap;
    }

    /**
     * 获取集群对应的节点硬盘使用率
     *
     * @param nodeIpList
     * @param diskSizesList
     * @param diskUsedsList
     * @param clusterName
     * @param condition
     * @return
     */
    public List<DiskConditonDTO> getDiskConditonInfo(String nodeIpList, String diskSizesList, String diskUsedsList,
            String clusterName, DashboardResourceInfoQueryDTO condition) {
        List<DiskConditonDTO> diskConditonDTOS = new ArrayList<>();
        List<String> nodeIps = Arrays.asList(nodeIpList.split(","));
        List<String> diskSizes = Arrays.asList(diskSizesList.split(","));
        List<String> diskUseds = Arrays.asList(diskUsedsList.split(","));

        for (int index = 0; index < nodeIps.size(); index++) {
            DiskConditonDTO diskConditonDTO = new DiskConditonDTO();
            diskConditonDTO.setNodeIp(nodeIps.get(index));
            double diskOccupancy =
                    new BigDecimal(Double.valueOf(diskUseds.get(index)) * 100 / Double.valueOf(diskSizes.get(index)))
                            .setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            diskConditonDTO.setDiskOccupancy(diskOccupancy);
            diskConditonDTO.setClusterName(clusterName);
            diskConditonDTOS.add(diskConditonDTO);
        }
        return diskConditonDTOS;
    }

    /*
     * 获取系统资源使用详情
     * 
     * @return
     */
    public List<DashboardResourceInfo> getDashboardResourceInfo() throws Exception {

        List<DashboardResourceInfo> resourceInfoList = new ArrayList<>();
        // 每一次采集数据唯一标识
        Date acquisitionTime = new Date();

        // 获取所有集群
        List<ClusterProperties.ClusterInfo> servers = clusterProperties.getServers();

        for (ClusterProperties.ClusterInfo clusterInfo : servers) {

            LOG.info("start to get core summary from cluster:{},type:{}", clusterInfo.getHost(),
                    clusterInfo.getEngineType());
            StorageCluster storageCluster = new StorageCluster(clusterInfo.getHost(), clusterInfo.getEngineType());

            // 集群节点总数
            int cluster_node_num = getclusterNodeNum(clusterInfo.getName());

            List<String> liveHostUrls = collectionManageFacade.getLiveHostUrl(storageCluster);

            // 返回solr集群或者es集群数据磁盘占有大小
            Map<String, com.pingan.haofang.searchcloud.api.DiskConditonDTO> diskConditonDTOMap =
                    collectionManageFacade.getNodesSummary(storageCluster);

            // 集群健康率
            double solrHealthRate = (double) diskConditonDTOMap.size() / cluster_node_num;

            // key 节点ip
            diskConditonDTOMap.forEach((k, v) -> {
                DashboardResourceInfo dashboardResourceInfo = new DashboardResourceInfo();

                dashboardResourceInfo.setClusterName(clusterInfo.getName());
                // 设置节点总数
                dashboardResourceInfo.setNodeNum(cluster_node_num);
                // 节点ip
                dashboardResourceInfo.setNodeIp(k);
                // 节点磁盘大小
                long diskSize = getclusterNodeDiskSize(k, clusterInfo.getName());
                dashboardResourceInfo.setDiskSize(diskSize);

                // 获取集群存活节点的磁盘占用量
                dashboardResourceInfo.setDiskUsed(v.getDiskUsed());
                double diskOccupancyRate = (double) v.getDiskUsed() / diskSize;
                // 预警判断
                checkDashboardResourceWrning(diskOccupancyRate, solrHealthRate, clusterInfo.getName(), k);

                // 存活节点
                dashboardResourceInfo.setStatus(NodeStatus.VALID.getValue());

                dashboardResourceInfo.setAcquisitionTime(acquisitionTime);
                resourceInfoList.add(dashboardResourceInfo);

            });

            // 死亡节点信息保存
            checkNodeStatus(liveHostUrls, clusterInfo, resourceInfoList, acquisitionTime);

        }
        return resourceInfoList;
    }

    /**
     * 获取死亡节点并存取
     *
     * @param liveHostUrls
     * @param clusterInfo
     * @param resourceInfoList
     * @return
     */
    public void checkNodeStatus(List<String> liveHostUrls, ClusterProperties.ClusterInfo clusterInfo,
            List<DashboardResourceInfo> resourceInfoList, Date acquisitionTime) {
        // 获取对应集群下的节点
        List<ClusterNodeProperties.ClusterNodeInfo> resources = getClusterNodeInfo(clusterInfo.getName());

        List<String> deadUrls = null;
        if (clusterInfo.getEngineType().getValue() == EngineType.ES.getValue()) {
            deadUrls = resources.stream().filter(t -> !liveHostUrls.contains(t.getHost())).map(t -> t.getHost())
                    .collect(Collectors.toList());
        } else {
            List<String> liveUrls = liveHostUrls.stream().map(t -> getIP(t)).collect(Collectors.toList());
            deadUrls = resources.stream().filter(t -> !liveUrls.contains(t.getHost())).map(t -> t.getHost())
                    .collect(Collectors.toList());
        }

        for (String url : deadUrls) {
            DashboardResourceInfo dashboardResourceInfo = new DashboardResourceInfo();
            dashboardResourceInfo.setClusterName(clusterInfo.getName());
            dashboardResourceInfo.setNodeIp(url);
            dashboardResourceInfo.setStatus(NodeStatus.INVALID.getValue());
            dashboardResourceInfo.setAcquisitionTime(acquisitionTime);
            dashboardResourceInfo.setNodeNum(resources.size());
            resourceInfoList.add(dashboardResourceInfo);
        }
    }

    /**
     * 获取集群中的节点总数
     *
     * @param clusterName
     * @return
     */
    public int getclusterNodeNum(String clusterName) {
        // 获取对应集群下的节点
        List<ClusterNodeProperties.ClusterNodeInfo> resources = getClusterNodeInfo(clusterName);
        return resources.size();
    }

    /**
     * 获取集群中的节点的磁盘大小
     *
     * @param clusterNodeHost
     * @return
     */
    public long getclusterNodeDiskSize(String clusterNodeHost, String clusterName) {
        // 获取所有集群下的节点
        long diskSize = 0;
        List<ClusterNodeProperties.ClusterNodeInfo> resources = getClusterNodeInfo(clusterName);

        if (resources.size() > 0) {
            Map<String, ClusterNodeProperties.ClusterNodeInfo> map = resources.stream()
                    .collect(Collectors.toMap(ClusterNodeProperties.ClusterNodeInfo::getHost, v -> v));

            diskSize = Optional.ofNullable(map.get(clusterNodeHost)).map(s -> s.getDiskSize()).orElse(0L);
        }

        return diskSize;
    }

    /**
     * 获取集群中的节点信息列表
     *
     * @param clusterName
     * @return
     */
    public List<ClusterNodeProperties.ClusterNodeInfo> getClusterNodeInfo(String clusterName) {
        // 获取所有集群节点信息
        List<ClusterNodeProperties.ClusterNodeInfo> servers = clusterNodeProperties.getNodes();

        Map<String, List<ClusterNodeProperties.ClusterNodeInfo>> map =
                servers.stream().collect(Collectors.groupingBy(ClusterNodeProperties.ClusterNodeInfo::getClusterName));

        return map.get(clusterName);
    }

    /**
     * 获得ip+端口号10.59.78.22:8983
     */
    public static String getIP(String url) {
        // 使用正则表达式过滤，
        String re =
                "((http|ftp|https)://)(([a-zA-Z0-9._-]+)|([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}))(([a-zA-Z]{2,6})|(:[0-9]{1,4})?)";
        String str = "";
        // 编译正则表达式
        Pattern pattern = Pattern.compile(re);
        // 忽略大小写的写法
        // Pattern pat = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(url);
        // 若url==http://127.0.0.1:9040或www.baidu.com的，正则表达式表示匹配
        if (matcher.matches()) {
            str = url;
        } else {
            String[] split2 = url.split(re);
            if (split2.length > 1) {
                String substring = url.substring(0, url.length() - split2[1].length());
                str = substring;
            } else {
                str = split2[0];
            }
        }
        return str.split("//")[1];
    }

    /*
     * 硬件预警发送邮件
     * 
     * @param diskOccupancyRate
     * 
     * @param solrHealthRate
     * 
     * @param clusterName
     * 
     * @param nodeIp
     */
    @Override
    public void checkDashboardResourceWrning(double diskOccupancyRate, double solrHealthRate, String clusterName,
            String nodeIp) {
        DecimalFormat df = new DecimalFormat("0");

        String disk_occupancyRate = df.format((double) (diskOccupancyRate * 100));

        String solr_healthRate = df.format((double) (solrHealthRate * 100));

        List<DashboardWarningConfig> configList = dashboardWarningConfigDao
                .findByWarningTypeAndStatus(WarningType.RESOURCE.getValue(), Status.NORMAL.getValue());

        JSONObject warningTrigger = new JSONObject();
        warningTrigger.put(MonitorIndicator.HARDWARE.SOLR_HEALTH_RATE, solr_healthRate);
        warningTrigger.put(MonitorIndicator.HARDWARE.DISK_OCCUPANCY_RATE, disk_occupancyRate);

        for (DashboardWarningConfig config : configList) {
            JSONObject jsonObject = (JSONObject) JSONObject.parse(config.getWarningConfig());

            int solr_health_rate = (int) jsonObject.get(MonitorIndicator.HARDWARE.SOLR_HEALTH_RATE);
            int disk_Occupancy_Rate = (int) jsonObject.get(MonitorIndicator.HARDWARE.DISK_OCCUPANCY_RATE);

            boolean flag = false;

            if (disk_Occupancy_Rate > 0 && disk_Occupancy_Rate <= 100
                    && Integer.valueOf(disk_occupancyRate) >= disk_Occupancy_Rate) {
                flag = true;
            }

            if (solr_health_rate > 0 && solr_health_rate <= 100
                    && Integer.valueOf(solr_healthRate) < solr_health_rate) {
                flag = true;
            }

            if (flag) {
                String warningContent = String.format("solr节点健康率设置为 %s%%,当前值 %s%% ," + "硬盘使用率设置为 %s%% , 当前值 %s%%",
                        solr_health_rate, solr_healthRate, disk_Occupancy_Rate, disk_occupancyRate);
                // save 预警历史
                DashboardWarningHistory warningHistory = new DashboardWarningHistory();
                warningHistory.setIndexId(null);
                warningHistory.setIndexName(nodeIp);
                warningHistory.setProjectId(null);
                warningHistory.setProjectName(clusterName);
                warningHistory.setConfigId(config.getId());
                warningHistory.setWarningTrigger(warningTrigger.toJSONString());
                dashboardWarningHistoryDao.save(warningHistory);

                // send
                MailDto<WarningModelDTO> mailDto = new MailDto<>();
                mailDto.setTemplateName(MailConstants.DASHBOARDRESOURCE_WARNING_TEMPLATE);
                mailDto.setEmailTo(Arrays.asList(config.getMailTo().split(",")));
                mailDto.setSubject(String.format(Constants.REPORT_TEMPLATE_MAIL_TITLE, env, "硬件预警", ""));

                WarningModelDTO warningModelDTO = new WarningModelDTO();
                warningModelDTO.setProjectName(clusterName);
                warningModelDTO.setIndexName(nodeIp);
                warningModelDTO.setContent(warningContent);
                mailDto.setModel(warningModelDTO);
                mailService.sendMail(mailDto);
            }
        }
    }
}
